package org.codefinger.json.serializer;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Map;

import org.codefinger.json.JSONBase;
import org.codefinger.json.util.IdentityCache;
import org.codefinger.json.util.IdentityCache.ValueBuilder;

public class JSONSerializerFactory {

	private static final IdentityCache<Class<?>, JSONSerializer>	JSONSERIALIZER_MAP	= new IdentityCache<Class<?>, JSONSerializer>(new JSONSerializerBuilder());

	static {
		JSONSERIALIZER_MAP.put(int.class, SerializerForInt.INSTANCE);
		JSONSERIALIZER_MAP.put(long.class, SerializerForLong.INSTANCE);
		JSONSERIALIZER_MAP.put(short.class, SerializerForShort.INSTANCE);
		JSONSERIALIZER_MAP.put(byte.class, SerializerForByte.INSTANCE);
		JSONSERIALIZER_MAP.put(boolean.class, SerializerForBoolean.INSTANCE);
		JSONSERIALIZER_MAP.put(char.class, SerializerForChar.INSTANCE);
		JSONSERIALIZER_MAP.put(double.class, SerializerForNumber.INSTANCE);
		JSONSERIALIZER_MAP.put(float.class, SerializerForNumber.INSTANCE);

		JSONSERIALIZER_MAP.put(int[].class, SerializerForIntArray.INSTANCE);
		JSONSERIALIZER_MAP.put(long[].class, SerializerForLongArray.INSTANCE);
		JSONSERIALIZER_MAP.put(short[].class, SerializerForShortArray.INSTANCE);
		JSONSERIALIZER_MAP.put(byte[].class, SerializerForByteArray.INSTANCE);
		JSONSERIALIZER_MAP.put(boolean[].class, SerializerForBooleanArray.INSTANCE);
		JSONSERIALIZER_MAP.put(char[].class, SerializerForCharArray.INSTANCE);
		JSONSERIALIZER_MAP.put(double[].class, SerializerForDoubleArray.INSTANCE);
		JSONSERIALIZER_MAP.put(float[].class, SerializerForFloatArray.INSTANCE);

		JSONSERIALIZER_MAP.put(Integer.class, SerializerForInt.INSTANCE);
		JSONSERIALIZER_MAP.put(Long.class, SerializerForLong.INSTANCE);
		JSONSERIALIZER_MAP.put(Short.class, SerializerForShort.INSTANCE);
		JSONSERIALIZER_MAP.put(Byte.class, SerializerForByte.INSTANCE);
		JSONSERIALIZER_MAP.put(Boolean.class, SerializerForBoolean.INSTANCE);
		JSONSERIALIZER_MAP.put(Character.class, SerializerForChar.INSTANCE);
		JSONSERIALIZER_MAP.put(Double.class, SerializerForNumber.INSTANCE);
		JSONSERIALIZER_MAP.put(Float.class, SerializerForNumber.INSTANCE);
		JSONSERIALIZER_MAP.put(BigDecimal.class, SerializerForNumber.INSTANCE);
		JSONSERIALIZER_MAP.put(BigInteger.class, SerializerForNumber.INSTANCE);
		JSONSERIALIZER_MAP.put(String.class, SerializerForString.INSTANCE);
		JSONSERIALIZER_MAP.put(Date.class, SerializerForDate.INSTANCE);
		JSONSERIALIZER_MAP.put(JSONBase.class, SerializerForJSONBase.INSTANCE);
	}

	private JSONSerializerFactory() {

	}

	public static void write(SerializerWriter writer, Object value) {
		if (value == null) {
			writer.writeNull();
			return;
		}
		getSerializer(value.getClass()).writeJSONString(writer, value);
	}

	public static JSONSerializer getSerializer(Class<?> type) {
		return JSONSERIALIZER_MAP.get(type);
	}

	private static class JSONSerializerBuilder implements ValueBuilder<Class<?>, JSONSerializer> {

		@Override
		public JSONSerializer build(Class<?> type) {
			if (type.isArray()) {
				return SerializerForArray.INSTANCE;
			} else if (type.isEnum()) {
				return SerializerForEnum.INSTANCE;
			} else if (Date.class.isAssignableFrom(type)) {
				return SerializerForDate.INSTANCE;
			} else if (Map.class.isAssignableFrom(type)) {
				return SerializerForMap.INSTANCE;
			} else if (Iterable.class.isAssignableFrom(type)) {
				return SerializerForCollection.INSTANCE;
			}
			return new SerializerForPojo(type);
		}

	}

}
